#!/usr/bin/env python
# this file is for adapt qingcloud python api
#
# Auth: Guosheng Cui 
#

import sys
import time
import logging
import qingcloud.iaas
from qingcloud.iaas.errors import InvalidParameterError
from qingcloud.iaas.sg_rule import SecurityGroupRuleFactory
from qingcloud.iaas.router_static import RouterStaticFactory
from qingcloud.iaas.lb_listener import LoadBalancerListener
from qingcloud.iaas.lb_backend import LoadBalancerBackend

import json
import six

from qing_cfg import QingConfig

def get_image_id(image):
    '''
    all the image are made by neucloud.com.
    '''
    
    return QingConfig.get_image_id(image)

def get_flavor_id(flavor):
    return QingConfig.get_flavor(flavor)

def build_userdata(resource, userdata=None, instance_user=None,
                   user_data_format='HEAT_CFNTOOLS'):
    pass

def get_network_id(network):
    '''
    it is a treater here
    '''
    return QingConfig.get_networdid(network)
    

def meta_serialize(metadata):
    """
    Serialize non-string metadata values before sending them to
    Nova.
    """
    return dict((key, (value if isinstance(value,
                                           six.string_types)
                       else json.dumps(value))
                 ) for (key, value) in metadata.items())

    

class CloudIaas():
    '''
    adapt layer of Qingcloud.
    TBD: all the ref api should be done with try catch 
    '''
    # sg
    DIRECTION_EGRESS = 1
    DIRECTION_INGRESS = 0

    # vxnet
    VXNET_TYPE_MANAGED = 1
    VXNET_TYPE_UNMANAGED = 0

    # lb
    BALANCE_ROUNDROBIN = "roundrobin"
    BALANCE_LEASTCONN = "leastconn"
    HEADER_X_FORWARD_FOR = 1
    HEADER_QC_LBID = 2
    HEADER_QC_LBIP = 4
    
    zone='gd1'
    access_key='PLGRTJLBWQOJVQVVHKRC'
    secret_key='ROCS1D8WTqiQnfhmRUaECjI3YFTSYT26OuIkA7E0'
    pek1conn = None
    gd1conn = None

    def __init__(self, access='', secret='', zone='gd1'):
        '''
        init the cloud instance
        '''
        
        if access != '':
            self.access_key = access

        if secret != '':
            self.secret_key = secret

        #add image id here
        self.image_id=['centos58x64',
          'centos58x86',
          'centos58x64',
          'centos63x64',
          'centos64x64a',
          'centos65x64',
          'centos65x64a',
          'wheezyx86',
          'wheezyx64a',
          'fedora18x86a',
          'fedora18x64a',
          'fedora20x64',
          'lucidsrvx64',
          'precisex64a',
          'quantalx64a',
          'opensuse12x64',
          'saucysrvx64',
          'hardysrvx86',
          'win2k3r2eechsa',
          'win2k8r2eechsa',
          'win2k8r2eeena',
          'winsrv2012r2chsa',
          'winserver2012chsa',
          'arch201310x64',
          'centos64x86']
        
        #logging.info('init the ' + self.zone + ' zone with key '+ self.access_key + ' = '+ self.secret_key)
        if CloudIaas.pek1conn == None:
            CloudIaas.pek1conn = qingcloud.iaas.connect_to_zone('pek1', CloudIaas.access_key, CloudIaas.secret_key)
        
        if CloudIaas.gd1conn == None:
            CloudIaas.gd1conn=qingcloud.iaas.connect_to_zone('gd1', CloudIaas.access_key, CloudIaas.secret_key)
        # no matter the input parameter is right or not, connect_to_zone always return success
        #self.conn = qingcloud.iaas.connect_to_zone(self.zone, self.access_key, self.secret_key)
        if zone == 'pek1':
            self.conn = CloudIaas.pek1conn
        elif zone == 'gd1':
            self.conn = CloudIaas.gd1conn
        else:
            self.conn = None

    def _chk_ret(self, ret, info):
        logging.info(ret)
        if ret['ret_code'] == 0:
            #create instance success
            logging.info(info + ' success')
        else:
            logging.error(info + ' failed')
            
        return ret['ret_code']

    def _chk_image_id(self, id):
        return True
        if id not in self.image_id:
            logging.ERROR("create instance failed, image_id "+ id +" not in image list") 
            return False
        
        return True       

    def create_instance_ex(self, image_id,
                                instance_type = None,
                                cpu = None,
                                memory = None,
                                count = 1,
                                instance_name = "",
                                vxnets = None,
                                security_group = None,
                                login_mode = None,
                                login_keypair = None,
                                login_passwd = None):
        if not self._chk_image_id(image_id):
            return (1, 'the input image wrong')
        
        ret = self.conn.run_instances(image_id, instance_type,
                                cpu,
                                memory,
                                count,
                                instance_name,
                                vxnets,
                                security_group,
                                login_mode,
                                login_keypair,
                                login_passwd)
        
        #check the ret here, return string as follow:
        #{u'action': u'RunInstancesResponse', u'instances': [u'i-fkyicor8'], u'job_id': u'j-12lu9xts', u'ret_code': 0}
    
        r = self._chk_ret(ret, 'create instance')

        if (r == 0):
            return (ret['ret_code'], ret['instances'])
        else:
            return (ret['ret_code'], ret['message'])
        
    def create_isntance(self, image_id, cpu = 1, mem = 512, cnt = 1, name = ""): 
        if not self._chk_image_id(image_id):
            return 1
        return self.create_instance_ex(image_id, cpu=cpu, memory=mem, count=cnt, instance_name=name)       
    
    def stop_instance(self, instance):
        '''
        stop a instance
        '''
        ret = self.conn.stop_instances(instances=instance, force=False)

        #return value as follow:
        #{u'action': u'StopInstancesResponse', u'job_id': u'j-dsvkvi63', u'ret_code': 0}
        r = self._chk_ret(ret, 'stop instance')
       
        if (r == 0):
            return (ret['ret_code'], )
        else:
            return (ret['ret_code'], ret['message'])
        
    def del_instance(self, instance):
        '''
        delete a instance
        '''
        ret = self.conn.terminate_instances(instances=instance)
        print ret
        #return value as follow:
        #{u'action': u'TerminateInstancesResponse', u'job_id': u'j-n2n92zey', u'ret_code': 0}
        r = self._chk_ret(ret, 'terminate instance')
        
        if (r == 0):
            return (ret['ret_code'], )
        else:
            return (ret['ret_code'], ret['message'])


    def _list_instance_ex(self, inst = None,
                                 type = None,
                                 stat = None,
                                 start = None,
                                 num = None):
        '''
        inst : the array of IDs of instances
        type: The instance type.
        stat : Status of the instance, including pending, running, stopped, terminated.
        start: the starting offset of the returning results.
        num: specify the number of the returning results.
        '''
        
        ret = self.conn.describe_instances(instances = inst,
                                 instance_type = type,
                                 status = stat,
                                 offset = start,
                                 limit = num)

        '''
        return value as follow:
        {u'action': u'DescribeInstancesResponse', u'instance_set': 
        [{u'vcpus_current': 1, u'instance_id': u'i-8iqkb3gx', u'vxnets': 
        [{u'vxnet_name': u'LAN_BJHESHU', u'vxnet_type': 1, u'vxnet_id': 
        u'vxnet-jmsdhra', u'nic_id': u'52:54:f5:0f:3f:ee', u'private_ip': None}], 
        u'memory_current': 512, u'sub_code': 0, u'transition_status': u'', 
        u'instance_name': u'test', u'instance_type': u'small_a', u'create_time': 
        u'2014-03-12T15:37:00Z', u'status': u'running', u'status_time': 
        u'2014-03-12T15:37:00Z', u'image': {u'processor_type': u'64bit', 
        u'platform': u'linux', u'image_size': 20, u'image_name': u'CentOS 6.5 64bit', 
        u'image_id': u'centos65x64', u'os_family': u'centos', u'provider': u'system'}, 
        u'description': None}], u'ret_code': 0, u'total_count': 1}
        '''
        return ret

    def _list_instance_by_stauts(self, status):
        ret = self._list_instance_ex(None, None, status, None, None)
        print ret
        if self._chk_ret(ret, 'list ' + str(status) + ' instance ') == 1:
            return (ret['ret_code'], ret['message'])
        return (ret['ret_code'], ret['instance_set'], ret['total_count'])        

    def list_run_instance(self):
        return self._list_instance_by_stauts(['running'])
    
    def list_stop_instance(self):
        return self._list_instance_by_stauts(['stopped'])

    def list_ceased_instance(self):
        return self._list_instance_by_stauts(['ceased'])

    def list_terminate_instance(self):
        return self._list_instance_by_stauts(['terminated'])
     
    def restart_instance(self, inst):
        """ 
        Restart one or more instances.
        inst : An array including IDs of the instances you want to restart.
        """
        
        ret = self.conn.restart_instances(inst)
        #{u'action': u'RestartInstancesResponse', u'job_id': u'j-y3bp8ifx', u'ret_code': 0}
        
        r = self._chk_ret(ret, "restart instance ")
        
        if r == 0:
            return (ret['ret_code'], )
        else:
            return (ret['ret_code'], ret['message'])

    def start_instances(self, inst):
        ret = self.conn.restart_instances(inst)
        r = self._chk_ret(ret, "start instance ")
        
        if r == 0:
            return (ret['ret_code'], )
        else:
            return (ret['ret_code'], ret['message'])        

    def reset_instances(self, inst):
        ret = self.conn.reset_instances(inst)
        r = self._chk_ret(ret, "reset instance ")        

        if r == 0:
            return (ret['ret_code'], )
        else:
            return (ret['ret_code'], ret['message'])
        
    def reset_instance_hw(self, instance,
                               cpu=None,
                               mem=None):
        """ reset one or more instances's hardware
        instance: the IDs of the instances you want to resize.
        instance_type: defined by qingcloud.
        cpu: cpu core number.
        mem: memory size in MB.
        """
        ret = self.conn.resize_instances(instances = instance, cpu=cpu, memory = mem)
        #{u'action': u'ResizeInstancesResponse', u'job_id': u'j-xht385ti', u'ret_code': 0}
        #{u'message': u'InvailidRequestFormat, memory size [512 MB] not allowed for CPU cores [2]', u'ret_code': 1100}
        r = self._chk_ret(ret, 'reset the instance hardware ')
        
        if r == 0:
            return (ret['ret_code'], )
        else:
            return (ret['ret_code'], ret['message'])

    def modify_instance_info(self, inst,
                                         name = None,
                                         desc = None,):
        '''
        Modify instance attributes.
        instance:  the ID of instance whose attributes you want to modify.
        instance_name: Name of the instance. It's a short name for the instance
                                  that more meaningful than instance id.
        description: The detailed description of the resource.
        '''
        ret = self.conn.modify_instance_attributes(instance = inst, instance_name = name, description = desc)
        
        #{u'action': u'ModifyInstanceAttributesResponse', u'ret_code': 0}
        r = self._chk_ret(ret, 'modify the instance info')
        if r == 0:
            return (ret['ret_code'], )
        else:
            return (ret['ret_code'], ret['message'])


    def list_image(self, images = None,
                              os_family = None,
                              processor_type = None,
                              status = None,
                              offset = None,
                              limit = None):
        '''
        list the image info
        images = None: an array including IDs of the images you want to list.
                       No ID specified means list all.
        os_family: os family, windows/debian/centos/ubuntu.               
        processor_type: supported processor types are `64bit` and `32bit`
        status: valid values include pending, available, deleted, ceased.
        offset: the starting offset of the returning results.
        limit: specify the number of the returning results.
        '''
        
        #it is for image, TBD
        ret = self.conn.describe_images()
        #print(ret['ret_code'], ret['instances'])
        return ret


    
    def list_volume(self, vol = None,
                               status = None,
                               start = None,
                               num = None):
        '''
        Describe volumes filtered by conditions
        volumes : the array of IDs of volumes.
        status: pending, available, in-use, deleted.
        offset: the starting offset of the returning results.
        limit: specify the number of the returning results.
        '''
        ret = self.conn.describe_volumes(volumes = vol,
                               instance_id = None,
                               status = status,
                               search_word = None,
                               verbose = 0,
                               offset = start,
                               limit = num)
        
        r = self._chk_ret(ret, 'list the volume info')
        '''
        {u'action': u'DescribeVolumesResponse', u'total_count': 2, u'volume_set': 
        [{u'status': u'in-use', u'description': u'', u'volume_name': u'disk1', 
        u'sub_code': 0, u'transition_status': u'', u'instance': {u'instance_id': 
        u'i-f0gdjmci', u'instance_name': u'fenghuo_centos_1'}, u'create_time': 
        u'2014-02-10T09:45:19Z', u'volume_id': u'vol-7ap68yj2', u'status_time': 
        u'2014-02-10T09:46:08Z', u'size': 50}, {u'status': u'in-use', u'description': 
        None, u'volume_name': u'disk2', u'sub_code': 0, u'transition_status': u'', 
        u'instance': {u'instance_id': u'i-gad0a8s9', u'instance_name': 
        u'fenghuo_centos_2'}, u'create_time': u'2014-02-10T09:46:18Z', u'volume_id': 
        u'vol-ans9tudk', u'status_time': u'2014-02-10T09:46:28Z', u'size': 50}], u'ret_code': 0}
        '''
        if r == 0:
            return (ret['ret_code'], ret['volume_set'], ret['total_count'])
        else:
            return (ret['ret_code'], ret['message'])
         
        
    def create_vol(self, size=64, name = "", cnt = 1):
        '''
        Create one or more volumes.
        size : the size of each volume. Unit is GB.
        name : the short name of volume
        cnt : the number of volumes to create.
        '''
        
        try:
            ret = self.conn.create_volumes(size=size, volume_name = name, count = cnt)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'create volume ')

            if r == 0:
                return (ret['ret_code'], ret['volumes'])
            else:
                return (ret['ret_code'], ret['message'])            

    def del_vol(self, vols):
        '''
        Delete one or more volumes.
        volumes : An array including IDs of the volumes you want to delete.
        '''
        
        try:
            ret = self.conn.delete_volumes(volumes = vols)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'delete volume ')

            if r == 0:
                return (ret['ret_code'], )
            else:
                return (ret['ret_code'], ret['message'])   
        
    def attach_vol(self, vol, inst):
        '''
        Attach one or more volumes to same instance
        vol : an array including IDs of the volumes you want to attach.
        inst : the ID of instance the volumes will be attached to.
        '''
        try:
            ret = self.conn.attach_volumes(volumes = vol, instance = inst)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'attach volume to instance ')

            if r == 0:
                return (ret['ret_code'], )
            else:
                return (ret['ret_code'], ret['message'])   
    
    def detach_vol(self, vol, inst):
        '''
        Detach one or more volumes from same instance.
        vol : An array including IDs of the volumes you want to attach.
        inst : the ID of instance the volumes will be detached from.
        '''
        try:
            ret = self.conn.detach_volumes(volumes = vol, instance = inst)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'detach volume to instance ')

            if r == 0:
                return (ret['ret_code'], )
            else:
                return (ret['ret_code'], ret['message'])  
            
    def change_vol(self, vol, size):
        """ 
        Extend one or more volumes' size.
        vol: The IDs of the volumes you want to resize.
        size : The new larger size of the volumes, unit is GB, it must be times of 10
        """
        try:
            ret = self.conn.resize_volumes(volumes = vol, size = size)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'change volume size ')

            if r == 0:
                return (ret['ret_code'], )
            else:
                return (ret['ret_code'], ret['message'])  

    def change_vol_info(self, vol, name = None, desc = None):
        '''
        Modify volume attributes.
        vol:  the ID of volume whose attributes you want to modify.
        name: Name of the volume. It's a short name for
                                the volume that more meaningful than volume id.
        desc: The detailed description of the resource.
        '''
        try:
            ret = self.conn.modify_volume_attributes(volume = vol, volume_name = name, description = desc)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'change volume info ')

            if r == 0:
                return (ret['ret_code'], )
            else:
                return (ret['ret_code'], ret['message'])  
            
        
    def list_keypairs(self, key = None,
                                 method = None,
                                 start = None,
                                 num = None):
        """ 
        Describe key-pairs filtered by condition
        key: IDs of the keypairs you want to describe.
        method: encrypt method.
        start: the starting offset of the returning results.
        num: specify the number of the returning results.
        """
        try:
            ret = self.conn.describe_key_pairs(keypairs = key,
                                 encrypt_method = method,
                                 search_word = None,
                                 verbose = 0,
                                 offset = start,
                                 limit = num)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'list key pair info ')

            if r == 0:
                return (ret['ret_code'], ret['keypair_set'], ret['total_count'])
            else:
                return (ret['ret_code'], ret['message'])  
        

    def create_keypair(self, name = '',
                             md = 'system',
                             method = "ssh-rsa",
                             key = None):
        """ 
        Create a keypair.
        name: the name of the keypair you want to create.
        md: the keypair creation mode, "system" or "user".
        method: the encrypt method, supported methods "ssh-rsa", "ssh-dss".
        key: provide your public key. (need "user" mode)
        """
        try:
            ret = self.conn.create_keypair(keypair_name = name,
                             mode = md,
                             encrypt_method = method,
                             public_key = key)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'create key pair ')

            if r == 0:
                return (ret['ret_code'], ret['private_key'], ret['keypair_id'])
            else:
                return (ret['ret_code'], ret['message'])  
        
    def del_keypairs(self, key):
        """ 
        Delete one or more keypairs.
        key: IDs of the keypairs you want to delete.
        """
        try:
            ret = self.conn.delete_keypairs(keypairs = key)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'delete key pairs ')

            if r == 0:
                return (ret['ret_code'], ret['keypairs'])
            else:
                return (ret['ret_code'], ret['message'])  
            
    def attach_keypairs(self, key, inst):
        """ 
        Attach one or more keypairs to instances.
        key: IDs of the keypairs you want to attach to instance .
        inst: IDs of the instances the keypairs will be attached to.
        """
        try:
            ret = self.conn.attach_keypairs(keypairs = key, instances = inst)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'attach key pairs ')

            if r == 0:
                return (ret['ret_code'], )
            else:
                return (ret['ret_code'], ret['message'])  
            
            
    def detach_keypairs(self, key, inst):
        """ 
        Detach one or more keypairs from instances.
        key: IDs of the keypairs you want to detach from instance .
        inst: IDs of the instances the keypairs will be detached from.
        """
        try:
            ret = self.conn.detach_keypairs(keypairs = key, instances = inst)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'attach key pairs ')

            if r == 0:
                return (ret['ret_code'], )
            else:
                return (ret['ret_code'], ret['message'])  
            
            
    def change_keypair_info(self, key, name = None, desc = None):
        """ 
        Modify keypair info.
        key: the ID of keypair you want to modify its attributes.
        name: the new name of keypair.
        desc: The detailed description of the resource.
        """
        try:
            ret = self.conn.modify_keypair_attributes(keypairs = key, keypair_name = name, description = desc)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'attach key pairs ')

            if r == 0:
                return (ret['ret_code'], )
            else:
                return (ret['ret_code'], ret['message'])  

    def list_security_groups(self, sg = None,
                                       name = None,
                                       start = None,
                                       num = None):
        """ 
        Describe security groups filtered by condition
        sg: IDs of the security groups you want to describe.
        name: the name of the security group.
        start: the starting offset of the returning results.
        num: specify the number of the returning results.
        """ 
        try:
            ret = self.conn.describe_security_groups(security_groups = sg,
                                       security_group_name = name,
                                       offset = start,
                                       limit = num)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'list security group  ')

            if r == 0:
                return (ret['ret_code'], ret['security_group_set'], ret['total_count'])
            else:
                return (ret['ret_code'], ret['message'])  

    def create_security_group(self, name):
        """ 
        Create a new security group without any rule.
        name: the name of the security group you want to create.
        """
        try:
            ret = self.conn.create_security_group(security_group_name = name)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'create security group  ')

            if r == 0:
                return (ret['ret_code'], ret['security_group_id'])
            else:
                return (ret['ret_code'], ret['message'])              
            
    def change_security_group_info(self, sg, name = None, desc = None):
        """ 
        Modify security group attributes.
        sg: the ID of the security group whose content you
            want to update.
        name: the new group name you want to update.
        desc: The detailed description of the resource.
        """
        try:
            ret = self.conn.modify_security_group_attributes(security_group=sg, 
                                                             security_group_name = name,
                                                             description = desc)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'change security group info ')

            if r == 0:
                return (ret['ret_code'], )
            else:
                return (ret['ret_code'], ret['message'])               
            
    def commit_security_group(self, sg,
                                   inst = None):
        """ 
        commit a security group with current rules.
            If `instances` specified, commit the security group to them,
            or will affect all instances that has applied this security group.
        sg: the ID of the security group that you want to commit to instances.
        inst: the IDs of the instances you want to commit the security group.
        """
        try:
            ret = self.conn.apply_security_group(security_group=sg, 
                                                             instances = inst)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'commit security group modification ')

            if r == 0:
                return (ret['ret_code'], )
            else:
                return (ret['ret_code'], ret['message'])               
            
    def del_security_groups(self, sg):
        """ 
        Delete one or more security groups.
        sg: the IDs of the security groups you want to delete.
        """
        try:
            ret = self.conn.delete_security_groups(security_groups = sg)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'delete security group ')

            if r == 0:
                return (ret['ret_code'], ret['security_groups'])
            else:
                return (ret['ret_code'], ret['message'])               
  
    def list_security_group_rules(self, sg = None,
                                            rule_ids = None,
                                            direct = None,
                                            start = None,
                                            num = None):
        """ 
        list security group rules filtered by condition.
        sg: the ID of the security group whose rules you want to describe.
        rule_ids: the IDs of the security group rules you want to describe.
        direct: 0 for inbound; 1 for outbound
        start: the starting offset of the returning results.
        num: specify the number of the returning results.
        """
        try:
            ret = self.conn.describe_security_group_rules(security_group = sg,
                                            security_group_rules = rule_ids,
                                            direction = direct,
                                            offset = start,
                                            limit = num)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'list security group rules ')

            if r == 0:
                return (ret['ret_code'], ret['security_group_rule_set'], ret['total_count'])
            else:
                return (ret['ret_code'], ret['message'])               

    def add_security_group_rules(self, sg, rules):
        """ 
        Add rules to security group.
        sg: the ID of the security group whose rules you
                                      want to add.
        rules: a list of rules you want to add,
                          can be created by SecurityGroupRuleFactory.
        """
        try:
            ret = self.conn.add_security_group_rules(security_group = sg,
                                            security_group_rules = rules)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'add security group rules ')

            if r == 0:
                
                return (ret['ret_code'], )
            else:
                return (ret['ret_code'], ret['message'])               

    #TBD create_security_group_rules
    def create_security_rule_form_str(self, str):
        """ 
        Create security group rule from json formatted string. the string must be json format
        """
        try:
            ret = SecurityGroupRuleFactory.create_from_string(str)
        except InvalidParameterError, e:
            logging(e)
            return (1, e)
        else:
            return ret
        
    def delete_security_group_rules(self, sgs):
        """ 
        Delete one or more security group rules.
        sgs: the IDs of rules you want to delete.
        """
        try:
            ret = self.conn.delete_security_group_rules(security_group = sgs)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'delete security group rules ')

            if r == 0:
                
                return (ret['ret_code'], ret['security_group_rules'])
            else:
                return (ret['ret_code'], ret['message'])   

    def change_security_group_rule(self, security_group_rule,
                                                    priority=None,
                                                    security_group_rule_name=None,
                                                    rule_action=None,
                                                    direction=None,
                                                    protocol=None,
                                                    val1=None,
                                                    val2=None,
                                                    val3=None):
        """ 
        Modify security group rule attributes.
        security_group_rule: the ID of the security group rule whose attributes you
                                      want to update.
        priority: priority [0 - 100].
        security_group_rule_name: name of the rule.
        rule_action: "accept" or "drop".
        direction: 0 for inbound; 1 for outbound.
        protocol: supported protocols are "icmp", "tcp", "udp", "gre".
        val1: for "icmp" protocol, this field is "icmp type";
                         for "tcp/udp", it's "start port", empty means all.
        val2: for "icmp" protocol, this field is "icmp code";
                         for "tcp/udp", it's "end port", empty means all.
        val3: ip network, e.g "1.2.3.0/24"
        """
        
        try:
            ret = self.conn.modify_security_group_rule_attributes(security_group_rule,
                                                    priority,
                                                    security_group_rule_name,
                                                    rule_action,
                                                    direction,
                                                    protocol,
                                                    val1,
                                                    val2,
                                                    val3)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'change security group rules ')

            if r == 0:
                
                return (ret['ret_code'], ret['security_group_rule_id'])
            else:
                return (ret['ret_code'], ret['message'])  


    def list_vxnets(self, nets = None,
                              start = None,
                              num = None):
        """ 
        Describe vxnets filtered by condition.
        nets: the IDs of vxnets you want to describe.
        start: the starting offset of the returning results.
        num: specify the number of the returning results.
        """
        try:
            ret = self.conn.describe_vxnets(vxnets = nets,
                              search_word = None,
                              verbose = 0,
                              limit = start,
                              offset = num)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'list virtual nets ')

            if r == 0:
                
                return (ret['ret_code'], ret['vxnet_set'], ret['total_count'])
            else:
                return (ret['ret_code'], ret['message'])  

    def create_vxnets(self, name,
                            type=VXNET_TYPE_MANAGED,
                            count=1):
        """ 
        Create one or more vxnets.
        name: the name of vxnet you want to create.
        type: vxnet type: unmanaged or managed.
        count:
        """
        try:
            ret = self.conn.create_vxnets(name, type, count)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'create virtual nets ')

            if r == 0:
                
                return (ret['ret_code'], ret['vxnets'])
            else:
                return (ret['ret_code'], ret['message'])  


    def join_vxnet(self, vxnet, instances):
        """ 
        One or more instances join the vxnet.
        vxnet : the id of vxnet you want the instances to join.
        instances : the IDs of instances that will join vxnet.
        """
        try:
            ret = self.conn.join_vxnet(vxnet, instances)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'join virtual nets ')

            if r == 0:
                
                return (ret['ret_code'], )
            else:
                return (ret['ret_code'], ret['message'])  

    def leave_vxnet(self, vxnet, instances):
        """ 
        One or more instances leave the vxnet.
        vxnet : The id of vxnet that the instances will leave.
        instances : the IDs of instances that will leave vxnet.
        """
        try:
            ret = self.conn.leave_vxnet(vxnet, instances)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'leave virtual nets ')

            if r == 0:
                
                return (ret['ret_code'], )
            else:
                return (ret['ret_code'], ret['message'])  
        
    def delete_vxnets(self, vxnets):
        """ 
        Delete one or more vxnets.
        vxnets: the IDs of vxnets you want to delete.
        """
        try:
            ret = self.conn.delete_vxnets(vxnets)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'delete virtual nets ')

            if r == 0:
                
                return (ret['ret_code'], ret['vxnets'])
            else:
                return (ret['ret_code'], ret['message'])  
        
    def change_vxnet_info(self, vxnet, name, desc):
        """ 
        Modify vxnet attributes
        vxnet: the ID of vxnet you want to modify its attributes.
        name: the new name of vxnet.
        desc: The detailed description of the resource.
        """
        try:
            ret = self.conn.modify_vxnet_attributes(vxnet, name, desc)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'change virtual nets info')

            if r == 0:
                
                return (ret['ret_code'], )
            else:
                return (ret['ret_code'], ret['message'])  
        
    def list_vxnet_instances(self, vxnet,
                                       type = None,
                                       status = None,
                                       start = None,
                                       num = None):
        """ 
        Describe instances in vxnet.
        vxnet: the ID of vxnet whose instances you want to describe.
        type: filter by instance type
        status: filter by status
        start: the starting offset of the returning results.
        num: specify the number of the returning results.
        """
        try:
            ret = self.conn.describe_vxnet_instances(vxnet,
                                       instances = None,
                                       image = None,
                                       instance_type = None,
                                       status = status,
                                       start = None,
                                       num = None,)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'change virtual nets info')

            if r == 0:
                
                return (ret['ret_code'], ret['instance_set'], ret['total_count'])
            else:
                return (ret['ret_code'], ret['message'])  
        
    def list_routes(self, routers = None,
                               net = None,
                               status = None,
                               num = None,
                               start = None):
        """ 
        Describe routers filtered by condition.
        routers: the IDs of the routers you want to describe.
        net: the ID of vxnet you want to describe.
        start: the starting offset of the returning results.
        num: specify the number of the returning results.
        """
        try:
            ret = self.conn.describe_routers(routers = routers,
                               vxnet = net,
                               status = status,
                               verbose = 0,
                               search_word = None,
                               limit = start,
                               offset = num)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'list routers ')

            if r == 0:
                
                return (ret['ret_code'], ret['router_set'], ret['total_count'])
            else:
                return (ret['ret_code'], ret['message'])

    def create_routers(self,
                             router_name=None,
                             count = 1,
                             security_group=None):
        """ 
        Create one or more routers.
        router_name: the name of the router.
        security_group: the ID of the security_group you want to apply to router.
        count: the count of router you want to create.
        """
        try:
            ret = self.conn.create_routers(count,
                             router_name,
                             security_group)
        except InvalidParameterError, e:
            print(ret)
            print('-----------')
            logging.error(e)
            print('-----------')
            return (1,e)
        else:
            r = self._chk_ret(ret, 'create routers ')

            if r == 0:
                
                return (ret['ret_code'], ret['routers'])
            else:
                return (ret['ret_code'], ret['message'])

    def delete_routers(self, routers):
        """ 
        Delete one or more routers.
        routers: the IDs of routers you want to delete.
        """
        try:
            ret = self.conn.delete_routers(routers)
        except InvalidParameterError, e:
            logging.error(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'delete routers ')

            if r == 0:
                
                return (ret['ret_code'],)
            else:
                return (ret['ret_code'], ret['message'])

    def commit_routers(self, routers):
        """ 
        commit one or more routers modification.
        routers: the IDs of routers you want to modify.
        """
        try:
            ret = self.conn.update_routers(routers)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'commit routers modification')

            if r == 0:
                
                return (ret['ret_code'],)
            else:
                return (ret['ret_code'], ret['message'])

    def poweroff_routers(self, routers):
        """ 
        Poweroff one or more routers.
        routers: the IDs of routers you want to poweroff.
        """
        try:
            ret = self.conn.poweroff_routers(routers)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'poweroff routers ')

            if r == 0:
                
                return (ret['ret_code'],)
            else:
                return (ret['ret_code'], ret['message'])

    def poweron_routers(self, routers):
        """ 
        Poweron one or more routers.
        routers: the IDs of routers you want to poweron.
        """
        try:
            ret = self.conn.poweron_routers(routers)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'poweron routers ')

            if r == 0:
                return (ret['ret_code'],)
            else:
                return (ret['ret_code'], ret['message'])

    def join_router(self, vxnet,
                          router,
                          ip_network,
                          manager_ip=None,
                          dyn_ip_start=None,
                          dyn_ip_end=None):
        """ 
        Connect vxnet to router.
        vxnet: the ID of vxnet that will join the router.
        router: the ID of the router the vxnet will join.
        ip_network: the ip network in CSI format.
        manager_ip: can be provided if DHCP feature is enabled.
        dyn_ip_start: starting IP that allocated from DHCP server.
        dyn_ip_end: ending IP that allocated from DHCP server.
        """
        try:
            ret = self.conn.join_router(vxnet,
                          router,
                          ip_network,
                          manager_ip,
                          dyn_ip_start,
                          dyn_ip_end)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'Connect vxnet to router ')

            if r == 0:
                return (ret['ret_code'],)
            else:
                return (ret['ret_code'], ret['message'])

    def leave_router(self, vxnet, router):
        """ 
        Disconnect vxnets from router.
        vxnets: the IDs of vxnets that will leave the router.
        router: the ID of the router the vxnet will leave.
        """
        try:
            ret = self.conn.leave_router(vxnet, router)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'Disconnect vxnets from router ')

            if r == 0:
                return (ret['ret_code'],)
            else:
                return (ret['ret_code'], ret['message'])

    def change_router_attributes(self, router,
                                       vxnet=None,
                                       eip=None,
                                       security_group=None,
                                       router_name=None,
                                       description=None,
                                       features=None,
                                       dyn_ip_start=None,
                                       dyn_ip_end=None):
        """ 
        Modify router attributes.
        router: the ID of router you want to modify its attributes.
        vxnet: the ID of vxnet whose feature you want to modify.
        eip: the eip.
        security_group: the ID of the security_group you want to apply to router.
        router_name: the name of the router.
        description: the description of the router.
        features: the features of vxnet you want to re-define. 1: enable DHCP; 0: disable DHCP
        dyn_ip_start: starting IP that allocated from DHCP server
        dyn_ip_end: ending IP that allocated from DHCP server
        """
        try:
            ret = self.conn.modify_router_attributes(router,
                                       vxnet,
                                       eip,
                                       security_group,
                                       router_name,
                                       description,
                                       features,
                                       dyn_ip_start,
                                       dyn_ip_end)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'Modify router attributes ')

            if r == 0:
                return (ret['ret_code'],)
            else:
                return (ret['ret_code'], ret['message'])

    def list_router_vxnets(self, router=None,
                                     vxnet=None,
                                     num=None,
                                     start=None):
        """ 
        list vxnets in router.
        router: filter by router ID.
        vxnet: filter by vxnet ID.
        start: the starting offset of the returning results.
        num: specify the number of the returning results.
        """
        try:
            ret = self.conn.describe_router_vxnets(router,
                                       vxnet, num, start)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'list vxnets in router ')

            if r == 0:
                return (ret['ret_code'], ret['router_vxnet_set'], ret['total_count'])
            else:
                return (ret['ret_code'], ret['message'])        

    def describe_router_statics(self, router_statics = None,
                                      router = None,
                                      vxnet = None,
                                      type = None,
                                      num = None,
                                      start = None):
        """ 
        list router statics filtered by condition.
        router_statics: the IDs of the router statics you want to describe.
        router: filter by router ID.
        vxnet: filter by vxnet ID.
        type: defined in `RouterStaticFactory`.
        start: the starting offset of the returning results.
        num: specify the number of the returning results.
        """
        try:
            ret = self.conn.describe_router_vxnets(router_statics,
                                      router,
                                      vxnet,
                                      type,
                                      num,
                                      start)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'list router statics filtered by condition ')

            if r == 0:
                return (ret['ret_code'], ret['router_static_set'], ret['total_count'])
            else:
                return (ret['ret_code'], ret['message'])  

    def add_router_statics(self, router,
                                 statics):
        """ 
        Add statics to router.
        router: the ID of the router whose statics you want to add.
        statics: a list of statics you want to add,
                            can be created by RouterStaticFactory.
        """
        try:
            ret = self.conn.add_router_statics(router, statics)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'Add statics to router')

            if r == 0:
                return (ret['ret_code'], ret['router_statics'])
            else:
                return (ret['ret_code'], ret['message'])  

    def delete_router_statics(self, router_statics):
        """ 
        Delete one or more router statics.
        router_statics: the IDs of router statics you want to delete.
        """
        try:
            ret = self.conn.add_router_statics(router_statics)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'Delete one or more router statics')

            if r == 0:
                return (ret['ret_code'], ret['router_statics'])
            else:
                return (ret['ret_code'], ret['message'])  

    def create_router_static_form_string(self, str):
        """ 
        Create router static from json formatted string.
        """
        try:
            ret = RouterStaticFactory.create_from_string(str)
        except InvalidParameterError, e:
            logging(e)
            return (1, e)
        else:
            return ret

    def list_eips(self, eips = None,
                            status = None,
                            start = None,
                            num = None):
        """ 
        list eips filtered by condition.
        eips: IDs of the eip you want describe.
        status: filter eips by status
        instance_id: filter eips by instance.
        search_word: search word column.
        offset: the starting offset of the returning results.
        limit: specify the number of the returning results.
        """
        try:
            ret = self.conn.describe_eips(eips,
                            status,
                            instance_id = None,
                            search_word = None,
                            offset = start,
                            limit = num)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'list eips filtered by condition')

            if r == 0:
                return (ret['ret_code'], ret['eip_set'], ret['total_count'])
            else:
                return (ret['ret_code'], ret['message'])  

    def associate_eip(self, eip, instance):
        """ 
        Associate an eip on an instance.
        eip: The id of eip you want to associate with instance.
        instance: the id of instance you want to associate eip.
        """
        try:
            ret = self.conn.associate_eip(eip, instance)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'Associate an eip on an instance')

            if r == 0:
                return (ret['ret_code'], )
            else:
                return (ret['ret_code'], ret['message'])  

    def dissociate_eips(self, eips):
        """ 
        Dissociate one or more eips.
        eips: The ids of eips you want to dissociate with instance.
        """
        try:
            ret = self.conn.dissociate_eips(eips)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'Dissociate one or more eips')

            if r == 0:
                return (ret['ret_code'], )
            else:
                return (ret['ret_code'], ret['message'])  

    def allocate_eips(self, bandwidth,
                            count=1,
                            need_icp=0,
                            eip_name=''):
        """ 
        Allocate one or more eips.
        count: the number of eips you want to allocate.
        bandwidth: the bandwidth of the eip in Mbps.
        need_icp:
        eip_name : the short name of eip
        """
        try:
            ret = self.conn.allocate_eips(bandwidth, count, need_icp, eip_name)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'Allocate one or more eips')

            if r == 0:
                return (ret['ret_code'], ret['eips'])
            else:
                return (ret['ret_code'], ret['message'])  

    def release_eips(self, eips, force=0):
        """ 
        Release one or more eips.
        eips : The ids of eips that you want to release
        force : Whether to force release the eip that needs icp codes.
        """
        try:
            ret = self.conn.release_eips(eips, force)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'Release one or more eips')

            if r == 0:
                return (ret['ret_code'], )
            else:
                return (ret['ret_code'], ret['message'])  

    def change_eips_bandwidth(self, eips, bandwidth):
        """ 
        Change one or more eips bandwidth.
        eips: The IDs of the eips whose bandwidth you want to change.
        bandwidth: the new bandwidth of the eip in MB.
        """
        try:
            ret = self.conn.change_eips_bandwidth(eips, bandwidth)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'Change one or more eips bandwidth')

            if r == 0:
                return (ret['ret_code'], )
            else:
                return (ret['ret_code'], ret['message'])  

    def change_eip_info(self, eip, eip_name=None, description=None):
        """ 
        Modify eip attributes.
        If you want to modify eip's bandwidth, use `change_eips_bandwidth`.
        eip : the ID of eip that you want to modify
        eip_name : the name of eip
        description : the eip description
        """
        try:
            ret = self.conn.modify_eip_attributes(eip, eip_name, description)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'Modify eip attributes')

            if r == 0:
                return (ret['ret_code'], )
            else:
                return (ret['ret_code'], ret['message'])  


    def describe_loadbalancers(self, loadbalancers=None,
                                      status=None,
                                      start=None,
                                      num=None):
        """ 
        list loadbalancers filtered by condition.

        loadbalancers : the array of load balancer IDs.
        status: pending, active, stopped, deleted, suspended, ceased
        start: the starting offset of the returning results.
        num: specify the number of the returning results.
        """
        try:
            ret = self.conn.describe_loadbalancers(loadbalancers,
                                      status,
                                      verbose=0,
                                      search_word=None,
                                      offset=start,
                                      limit=num)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'list loadbalancers filtered by condition')

            if r == 0:
                return (ret['ret_code'], ret['loadbalancer_set'], ret['total_count'])
            else:
                return (ret['ret_code'], ret['message'])  

    def create_loadbalancer(self, eips, loadbalancer_name=None, security_group=None):
        """ 
        Create new load balancer.

        eips: the IDs of the eips that will be associated to load balancer.
        loadbalancer_name: the name of the loadbalancer.
        security_group: the id of the security_group you want to apply to loadbalancer,
                                   use `default security` group as default.
        """
        try:
            ret = self.conn.create_loadbalancer(eips, loadbalancer_name, security_group)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'Create new load balancer')

            if r == 0:
                return (ret['ret_code'], ret['loadbalancer_id'])
            else:
                return (ret['ret_code'], ret['message'])

    def delete_loadbalancers(self, loadbalancers):
        """ 
        Delete one or more load balancers.
        loadbalancers: the IDs of load balancers you want to delete.
        """
        try:
            ret = self.conn.delete_loadbalancers(loadbalancers)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'Delete one or more load balancers')

            if r == 0:
                return (ret['ret_code'], )
            else:
                return (ret['ret_code'], ret['message'])
        

    def stop_loadbalancers(self, loadbalancers):
        """ 
        Stop one or more load balancers.

        loadbalancers: the array of load balancer IDs.
        """
        try:
            ret = self.conn.stop_loadbalancers(loadbalancers)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'Stop one or more load balancers')

            if r == 0:
                return (ret['ret_code'], )
            else:
                return (ret['ret_code'], ret['message'])
        

    def start_loadbalancers(self, loadbalancers):
        """ 
        Start one or more load balancers.

        loadbalancers: the array of load balancer IDs.
        """
        try:
            ret = self.conn.start_loadbalancers(loadbalancers)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'Start one or more load balancers')

            if r == 0:
                return (ret['ret_code'], )
            else:
                return (ret['ret_code'], ret['message'])
        

    def commit_loadbalancers(self, loadbalancers):
        """ 
        commit one or more load balancers.

        loadbalancers: the array of load balancer IDs.
        """
        try:
            ret = self.conn.update_loadbalancers(loadbalancers)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'commit one or more load balancers')

            if r == 0:
                return (ret['ret_code'], )
            else:
                return (ret['ret_code'], ret['message'])
        

    def associate_eips_to_loadbalancer(self, loadbalancer, eips):
        """ 
        Associate one or more eips to load balancer.

        loadbalancer: the ID of load balancer.
        eips: the array of eip IDs.
        """
        try:
            ret = self.conn.associate_eips_to_loadbalancer(loadbalancer, eips)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'Associate one or more eips to load balancer')

            if r == 0:
                return (ret['ret_code'], )
            else:
                return (ret['ret_code'], ret['message'])


    def dissociate_eips_from_loadbalancer(self, loadbalancer, eips):
        """ 
        Dissociate one or more eips from load balancer.

        loadbalancer: the ID of load balancer.
        eips: the array of eip IDs.
        """
        try:
            ret = self.conn.dissociate_eips_from_loadbalancer(loadbalancer, eips)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'Dissociate one or more eips from load balancer')

            if r == 0:
                return (ret['ret_code'], )
            else:
                return (ret['ret_code'], ret['message'])


    def change_loadbalancer_attributes(self, loadbalancer,
                                             security_group=None,
                                             loadbalancer_name=None,
                                             description=None):
        """
        Modify load balancer attributes.

        loadbalancer: the ID of loadbalancer you want to modify.
        security_group: the ID of the security_group.
        loadbalancer_name: the name of the loadbalancer.
        description: the description of the loadbalancer.
        """
        try:
            ret = self.conn.modify_loadbalancer_attributes(loadbalancer, security_group, 
                                                           loadbalancer_name, description)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'Modify load balancer attributes')

            if r == 0:
                return (ret['ret_code'], )
            else:
                return (ret['ret_code'], ret['message'])


    def list_loadbalancer_listeners(self, loadbalancer_listeners=None,
                                              loadbalancer=None,
                                              num=None,
                                              start=None):
        """ 
        Describe load balancer listeners by filter condition.

        loadbalancer_listeners: filter by load balancer listener IDs.
        loadbalancer: filter by loadbalancer ID.
        verbose: the number to specify the verbose level, larger the number, the more detailed information will be returned.
        start: the starting offset of the returning results.
        num: specify the number of the returning results.
        """
        try:
            ret = self.conn.describe_loadbalancer_listeners(loadbalancer_listeners,
                                              loadbalancer,
                                              verbose=0,
                                              limit=num,
                                              offset=start)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'Describe load balancer listeners by filter condition')

            if r == 0:
                return (ret['ret_code'], ret['loadbalancer_listener_set'], ret['total_count'])
            else:
                return (ret['ret_code'], ret['message'])
        

    def add_listeners_to_loadbalancer(self, loadbalancer, listeners):

        """ 
        Add listeners to load balancer.

        loadbalancer: The ID of loadbalancer.
        listeners: the listeners to add.
        """
        try:
            ret = self.conn.add_listeners_to_loadbalancer(loadbalancer,
                                            listeners)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'Add listeners to load balancer')

            if r == 0:
                #TBD: the return value should be checked
                return (ret['ret_code'], ret['loadbalancer_listeners'])
            else:
                return (ret['ret_code'], ret['message'])
        

    def delete_loadbalancer_listeners(self, loadbalancer_listeners):

        """ 
        Delete load balancer listeners.

        loadbalancer_listeners: the array of listener IDs.
        """
        try:
            ret = self.conn.delete_loadbalancer_listeners(loadbalancer_listeners)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'Delete load balancer listeners')

            if r == 0:
                #TBD: the return value should be checked
                return (ret['ret_code'], ret['loadbalancer_listeners'])
            else:
                return (ret['ret_code'], ret['message'])


    def change_loadbalancer_listener(self, loadbalancer_listener,
                                                      loadbalancer_listener_name=None,
                                                      balance_mode=None,
                                                      forwardfor=None,
                                                      healthy_check_method=None,
                                                      healthy_check_option=None,
                                                      session_sticky=None):
        """ 
        Modify load balancer listener attributes

        loadbalancer_listener: the ID of listener.
        loadbalancer_listener_name: the name of the listener.
        balance_mode: defined in constants.py,
                        BALANCE_ROUNDROBIN, BALANCE_LEASTCONN
        forwardfor: extra http headers, represented as bitwise flag defined in constants.py,
                        HEADER_QC_LB_IP, HEADER_QC_LB_ID and HEADER_X_FORWARD_FOR.
                        Example: if you need X-Forwarded-For and QC-LB-IP in http header,
                        then forwardfor should be HEADER_X_FORWARD_FOR | HEADER_QC_LB_IP.
        description: the description of the listener.
        """
        try:
            ret = self.conn.modify_loadbalancer_listener_attributes(loadbalancer_listener,
                                                      loadbalancer_listener_name,
                                                      balance_mode,
                                                      forwardfor,
                                                      healthy_check_method,
                                                      healthy_check_option,
                                                      session_sticky)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'Modify load balancer listener attributes')

            if r == 0:
                #TBD: the return value should be checked
                return (ret['ret_code'], )
            else:
                return (ret['ret_code'], ret['message'])


    def list_loadbalancer_backends(self, loadbalancer_backends=None,
                                             loadbalancer_listener=None,
                                             loadbalancer=None,
                                             num=None,
                                             start=None):
        """ 
        Describe load balancer backends.

        loadbalancer_backends: filter by load balancer backends ID.
        loadbalancer_listener: filter by load balancer listener ID.
        loadbalancer: filter by load balancer ID.
        start: the starting offset of the returning results.
        num: specify the number of the returning results.
        """
        try:
            ret = self.conn.describe_loadbalancer_backends(loadbalancer_backends,
                                             loadbalancer_listener,
                                             loadbalancer,
                                             verbose=0,
                                             limit=num,
                                             offset=start)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'Describe load balancer backends')

            if r == 0:
                #TBD: the return value should be checked
                return (ret['ret_code'], ret['loadbalancer_backend_set'], ret['total_count'])
            else:
                return (ret['ret_code'], ret['message'])


    def add_backends_to_listener(self, loadbalancer_listener,
                                       backends):
        """ 
        Add one or more backends to load balancer listener.

        loadbalancer_listener: the ID of load balancer listener
        backends: the load balancer backends to add
        """
        try:
            ret = self.conn.add_backends_to_listener(loadbalancer_listener,
                                       backends)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'Add one or more backends to load balancer listener')

            if r == 0:
                #TBD: the return value should be checked
                return (ret['ret_code'], ret['loadbalancer_backends'])
            else:
                return (ret['ret_code'], ret['message'])
        

    def delete_loadbalancer_backends(self, backends):
        """ 
        Delete load balancer backends.

        backends: the array of backends IDs.
        """
        try:
            ret = self.conn.delete_loadbalancer_backends(backends)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'Delete load balancer backends')

            if r == 0:
                #TBD: the return value should be checked
                return (ret['ret_code'], ret['loadbalancer_backends'])
            else:
                return (ret['ret_code'], ret['message'])


    def change_loadbalancer_backend_attributes(self, loadbalancer_backend,
                                                     loadbalancer_backend_name=None,
                                                     port=None,
                                                     weight=None):
        """ 
        Modify load balancer backend attributes.

        loadbalancer_backend: the ID of backend.
        loadbalancer_backend_name: the name of the backend.
        port: backend server listen port.
        weight: backend server weight, valid range is from 1 to 100.
        """
        try:
            ret = self.conn.modify_loadbalancer_backend_attributes(loadbalancer_backend,
                                                     loadbalancer_backend_name,
                                                     port,
                                                     weight)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'Delete load balancer backends')

            if r == 0:
                #TBD: the return value should be checked
                return (ret['ret_code'], )
            else:
                return (ret['ret_code'], ret['message'])


    def create_loadbalancer_listener_from_str(self, str):
        """
        Create load balancer listener from json formatted string.
        """
        try:
            ret = LoadBalancerListener.create_from_string(str)
        except InvalidParameterError, e:
            logging(e)
            return (1, e)
        else:
            return ret


    def create_loadbalancer_backend_from_str(self, str):
        """
        Create load balancer backend from json formatted string.
        """
        try:
            ret = LoadBalancerBackend.create_from_string(str)
        except InvalidParameterError, e:
            logging(e)
            return (1, e)
        else:
            return ret


    def get_monitoring_data(self, resource,
                                  meters,
                                  step,
                                  start_time,
                                  end_time,
                                  decompress=False):
        """ 
        Get resource monitoring data.

        resource: the ID of resource, can be instance_id, volume_id, eip_id or router_id.
        meters: list of metering types you want to get.
                           If resource is instance, meter can be "cpu", "disk-os", "memory",
                           "disk-%s" % attached_volume_id, "if-%s" % vxnet_mac_address.
                           If resource is volume, meter should be "disk-%s" % volume_id.
                           If resource is eip, meter should be "traffic".
                           If resource is router, meter can be "vxnet-0" and joint vxnet ID.
        step: The metering time step, valid steps: "5m", "15m", "30m", "1h", "2h", "1d".
        start_time: the starting UTC time, in the format YYYY-MM-DDThh:mm:ssZ.
        end_time: the ending UTC time, in the format YYYY-MM-DDThh:mm:ssZ.
        """
        try:
            ret = self.conn.get_monitoring_data(resource,
                                  meters,
                                  step,
                                  start_time,
                                  end_time,
                                  decompress)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'Get resource monitoring data')

            if r == 0:
                #TBD: the return value should be checked
                return (ret['ret_code'], ret['resource_id'], ret['meter_set'])
            else:
                return (ret['ret_code'], ret['message'])        
    

    def get_loadbalancer_monitoring_data(self, resource,
                                               meters,
                                               step,
                                               start_time,
                                               end_time,
                                               decompress=False):
        """ 
        Get load balancer monitoring data.

        resource: the ID of resource, can be loadbalancer_id, listener_id or backend_id.
        meters: list of metering types you want to get, valid values: request, traffic.
        step: The metering time step, valid steps: "5m", "15m", "30m", "1h", "2h", "1d".
        start_time: the starting UTC time, in the format YYYY-MM-DDThh:mm:ssZ.
        end_time: the ending UTC time, in the format YYYY-MM-DDThh:mm:ssZ.
        """
        try:
            ret = self.conn.get_monitoring_data(resource,
                                  meters,
                                  step,
                                  start_time,
                                  end_time,
                                  decompress)
        except InvalidParameterError, e:
            logging(e)
            return (1,e)
        else:
            r = self._chk_ret(ret, 'Get load balancer monitoring data')

            if r == 0:
                #TBD: the return value should be checked
                return (ret['ret_code'], ret['resource_id'], ret['meter_set'])
            else:
                return (ret['ret_code'], ret['message']) 



        
    



class ScheduleVm():
    vmlist = []
    startTime=''
    shutTime=''

    qing = CloudIaas()
    def start(self):
        self.qing.start_instance(self.vmlist)
        
    def stop(self):
        self.qing.stop_instance(self.vmlist)




class TestQing():
    
    
    def test_vm(self):
        tt = CloudIaas()
        ret = tt.create_isntance('centos65x64a', 1, 512, 1, 'test')
        print ret
        if(ret[0] != 0):
            logging.info("failed")
            return
    
        vm=ret[1]
    
    
        print vm    
        print('list run instance')
        tt.list_run_instance()
    
        print('list stop instance')
        tt.list_stop_instance()
    
        print('list terminated instance')
        tt.list_terminate_instance()
    
        print("list cease instance")
        tt.list_ceased_instance()


        time.sleep(40)
        print('restart the instance')
        while tt.restart_instance(vm)[0] != 0:
            time.sleep(20)
    
        time.sleep(40)
        print("reset the instance")
        while tt.reset_instances(vm)[0] != 0:
            time.sleep(20)
    
            time.sleep(40)
            print('reset the instance hardware')
            tt.reset_instance_hw(vm, cpu=1, mem=512)
    
    
            time.sleep(40)
            print('reset the instance info')
            tt.modify_instance_info(vm[0], name='xxxx', desc='this is for test')
    
    
            time.sleep(40)
            print(vm)
            print('stop the instance info')
            while tt.stop_instance(vm)[0] != 0:
                time.sleep(10)

            print(vm)
            time.sleep(40)
            print('delete the instance info')
            while tt.del_instance(vm)[0] != 0:
                time.sleep(2)
    
            print('success')


    def test_vol(self):
        tt = CloudIaas()
            
        ret = tt.create_isntance('centos65x64a', 1, 512, 1, 'test')
        print ret
        if(ret[0] != 0):
            logging.info("failed")
            return
            
        vm = ret[1]
            
        print('create volume test')
        ret = tt.create_vol(10, 'test_vol', 1)
        if ret[0] == 0:
            vol=ret[1]
        else:
            print ('create vol failed')
            return
            
        print vol
        print vm
            
        time.sleep(30)
        print('attach volume test')
        ret = tt.attach_vol(vol, vm)
        if ret[0] != 0:
            print('attache vol to vm failed')
            print(ret)
            return
                
        time.sleep(30)
        print('detach volume test')
        ret = tt.detach_vol(vol, vm)
        if ret[0] != 0:
            print('detach vol from vm failed')
            return
        
        time.sleep(30)

        print('list volume test')
        ret = tt.list_volume(vol)
        if ret[0] != 0:
            print('list vol failed')
            return
            
        print ret[1]
        time.sleep(20)
        print('change vol test')
        ret = tt.change_vol(vol, 20)
        if ret[0] != 0:
            print('change vol failed')
            print(ret)
            return
        time.sleep(20)
            
        
        print('change vol info test')
        ret = tt.change_vol_info(vol, 'hhhhh', "this is for test")
        if ret[0] != 0:
            print('change vol failed')
            print(ret)
            return
        
            
        time.sleep(20)
        print('del vol test')
        ret = tt.del_vol(vol)
        if ret[0] != 0:
            print('del vol failed')
            print(ret)
                
        tt.del_instance(vm)
        
    
    


if __name__ == "__main__":
    '''
    TEST FOR THIS CLASS
    '''
    
    print 'test for vm'
    t = TestQing()
    #tt.test_vm()
    t.test_vol()
